package socketmvc.server.tcp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.Node;
import org.tio.server.AcceptCompletionHandler;
import org.tio.server.TioServer;
import org.tio.server.TioServerConfig;
import org.tio.utils.hutool.StrUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.TimeUnit;

public class TcpServer extends TioServer{

    private static final Logger log = LoggerFactory.getLogger(TcpServer.class);
    private TioServerConfig tioServerConfig;
    private AsynchronousServerSocketChannel serverSocketChannel;
    private AsynchronousChannelGroup channelGroup = null;
    private Node serverNode;
    private boolean isWaitingStop = false;
    private boolean checkLastVersion = true;

    public TcpServer(TioServerConfig tioServerConfig) {
        super(null);
        this.tioServerConfig = tioServerConfig;
    }

    public TioServerConfig getTioServerConfig() {
        return this.tioServerConfig;
    }

    public Node getServerNode() {
        return this.serverNode;
    }

    public AsynchronousServerSocketChannel getServerSocketChannel() {
        return this.serverSocketChannel;
    }

    public boolean isWaitingStop() {
        return this.isWaitingStop;
    }

    public void setTioServerConfig(TioServerConfig tioServerConfig) {
        this.tioServerConfig = tioServerConfig;
    }

    public void setWaitingStop(boolean isWaitingStop) {
        this.isWaitingStop = isWaitingStop;
    }

    public void start(String serverIp, int serverPort) throws IOException {
        this.serverNode = new Node(serverIp, serverPort);
        channelGroup = AsynchronousChannelGroup.withThreadPool(tioServerConfig.groupExecutor);
        serverSocketChannel = AsynchronousServerSocketChannel.open(channelGroup);
        serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
        serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 64 * 1024);
        InetSocketAddress listenAddress = null;
        if (StrUtil.isBlank(serverIp)) {
            listenAddress = new InetSocketAddress(serverPort);
        } else {
            listenAddress = new InetSocketAddress(serverIp, serverPort);
        }
        serverSocketChannel.bind(listenAddress, 0);
        AcceptCompletionHandler acceptCompletionHandler = tioServerConfig.getAcceptCompletionHandler();
        serverSocketChannel.accept(this, acceptCompletionHandler);
        tioServerConfig.startTime = System.currentTimeMillis();

        String printStr = """
                
                --------------------------------------------------------------------------------------------------------
                    socketmvc server start successfully! server name is %s , listen on %s.
                --------------------------------------------------------------------------------------------------------
                """.formatted(this.tioServerConfig.getName(),this.getServerNode().toString());
        if (log.isInfoEnabled()) {
            log.info(printStr);
        } else {
            System.out.println(printStr);
        }

    }

    public boolean stop() {
        this.isWaitingStop = true;
        boolean ret = true;

        try {
            this.channelGroup.shutdownNow();
        } catch (Exception var6) {
            log.error("channelGroup.shutdownNow()时报错", var6);
        }

        try {
            this.serverSocketChannel.close();
        } catch (Exception var5) {
            log.error("serverSocketChannel.close()时报错", var5);
        }

        try {
            this.tioServerConfig.groupExecutor.shutdown();
        } catch (Exception var4) {
            log.error(var4.toString(), var4);
        }

        try {
            this.tioServerConfig.tioExecutor.shutdown();
        } catch (Exception var3) {
            log.error(var3.toString(), var3);
        }

        this.tioServerConfig.setStopped(true);

        try {
            ret = ret && this.tioServerConfig.groupExecutor.awaitTermination(6000L, TimeUnit.SECONDS);
            ret = ret && this.tioServerConfig.tioExecutor.awaitTermination(6000L, TimeUnit.SECONDS);
        } catch (InterruptedException var7) {
            log.error(var7.getLocalizedMessage(), var7);
        }

        log.info(this.serverNode + " stopped");
        return ret;
    }

    public boolean isCheckLastVersion() {
        return this.checkLastVersion;
    }

    public void setCheckLastVersion(boolean checkLastVersion) {
        log.debug("community edition is no longer supported");
    }
}
